/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd;

import java.lang.reflect.Method;
import java.util.List;

import org.zhiqim.kernel.Z;
import org.zhiqim.kernel.model.maps.HashMapSO;
import org.zhiqim.kernel.model.maps.HashMapSS;
import org.zhiqim.kernel.model.maps.MapSV;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.Ints;
import org.zhiqim.kernel.util.Longs;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Types;

/**
 * HTTP在线用户定义，子类继承时，需设置到HttpSessionManager中
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public abstract class HttpSessionUser
{
    protected transient HttpSession session;
    
    //两个冗余的字段，用于生成JSON时可以通过字符串找到对应的类名和字段
    protected String className;
    protected String sessionName;
    
    //通用的值表，和session中的attributeMap不同的是：
    //1.valueMap绑定sessionUser，解绑即失效
    //2.attributeMap可用在和sessionUser无关的地方
    protected transient HashMapSO valueMap = new HashMapSO();
    protected transient HashMapSS valueGenerics = new HashMapSS();
    
    //非本系统的会话用户属性的，多系统共享会话时会出现
    protected transient HashMapSS moreMap = new HashMapSS();
    
    public HttpSessionUser()
    {
        className = this.getClass().getName();
    }
    
    /*******************************************************************/
    //要求子类强制实现的方法
    /*******************************************************************/
    
    public abstract String getSessionName();
    
    /*******************************************************************/
    //由HttpSessionUser子类针对Session在远端的，有修改属性的时候同步到远端
    /*******************************************************************/
    
    public void flush()
    {
        session.flush();
    }
    
    /*******************************************************************/
    //获取HttpSession对象和相关属性
    /*******************************************************************/
    
    public String getClassName()
    {
        return className;
    }
    
    public HttpSession getSession()
    {
        return session;
    }
    
    public HttpContext getContext()
    {
        return session.getContext();
    }
    
    public String getSessionId()
    {
        return session.getId();
    }
    
    public boolean isNew()
    {
        return session.isNew();
    }
    
    public String getSessionIp()
    {
        return session.getUserIp();
    }
    
    public String getUserAgent()
    {
        return session.getUserAgent();
    }
    
    public long getCreated()
    {
        return session.getCreated();
    }
    
    public String getCreateTime()
    {
        return session.getCreateTime();
    }
    
    public long getLastAccessed()
    {
        return session.getLastAccessed();
    }
    
    public String getLastAccessTime()
    {
        return session.getLastAccessTime();
    }
    
    public long getRemainSecond()
    {
        return session.getRemainSecond();
    }
    
    public long getRemainMinute()
    {
        return session.getRemainMinute();
    }
    
    public long[] getRemainTime()
    {
        return session.getRemainTime();
    }
    
    public String getRemainTimeDesc()
    {
        return session.getRemainTimeDesc();
    }
    
    /***************************************************************/
    //读写关联到HttpSession中attribute列表
    /***************************************************************/
    
    public HashMapSO getAttributes()
    {
        return session.getAttributes();
    }
    
    public Object getAttribute(String name)
    {
        return session.getAttribute(name);
    }
    
    public Object removeAttribute(String name)
    {
        return session.removeAttribute(name);
    }
    
    public void setAttribute(String name, Object value)
    {
        session.setAttribute(name, value);
    }
    
    public void setAttribute(String name, Object value, Class<?> genericClass)
    {
        session.setAttribute(name, value, genericClass);
    }
    
    public boolean hasAttribute(String name)
    {
        return session.hasAttribute(name);
    }

    /***************************************************************/
    //读写关联到HttpSessionUser自己的参数列表
    /***************************************************************/

    public Object removeValue(String key)
    {
        valueGenerics.remove(key);
        Object val = valueMap.remove(key);
        flush();
        return val;
    }
    
    public void setValue(String key, Object value)
    {
        Asserts.as(!(value instanceof List || value instanceof MapSV)?null:"本方法不支持List<T>和MapSV<V>，请使用有泛型参数的setAttribute方法");
        
        valueMap.put(key, value);
        flush();
    }
    
    public void setValue(String key, Object value, Class<?> genericClass)
    {
        Asserts.as((value instanceof List || value instanceof MapSV)?null:"本方法仅支持List<T>和MapSV<V>，请使用无泛型参数的setAttribute方法");
        
        valueMap.put(key, value);
        valueGenerics.put(key, genericClass.getName());
        flush();
    }
    
    public void setValueTrue(String key)
    {
        setValue(key, true);
    }
    
    public void setValueFalse(String key)
    {
        setValue(key, false);
    }
    
    public HashMapSO getValues()
    {
        return valueMap;
    }
    
    public Object getValue(String key)
    {
        return valueMap.get(key);
    }
    
    public boolean hasValue(String key)
    {
        return valueMap.containsKey(key);
    }
    
    public String getValueString(String key)
    {
        return getValueString(key, null);
    }
    
    public String getValueString(String key, String defaultValue)
    {
        Object value = getValue(key);
        return (value == null)?defaultValue:Strings.trim(String.valueOf(value));
    }
    
    public int getValueInt(String key)
    {
        return getValueInt(key, -1);
    }
    
    public int getValueInt(String key, int defaultValue)
    {
        return Ints.toInt(valueMap.get(key), defaultValue);
    }
    
    public long getValueLong(String key)
    {
        return getValueLong(key, -1);
    }
    
    public long getValueLong(String key, long defaultValue)
    {
        return Longs.toLong(valueMap.get(key), defaultValue);
    }
    
    public boolean getValueBoolean(String key, boolean defaultValue)
    {
        Object value = valueMap.get(key);
        if (value == null)
            return defaultValue;
        else if (value instanceof Boolean)
            return (Boolean)value;
        else if (value instanceof String)
            return Boolean.parseBoolean((String)value);
        else
            return defaultValue;
    }
    
    @SuppressWarnings("unchecked")
    public <T> T getValueObj(String key, Class<T> genericClass)
    {
        Object value = valueMap.get(key);
        if (value == null)
            return null;
        
        return (T)value;
    }
    
    @SuppressWarnings("unchecked")
    public <T> List<T> getValueList(String key, Class<T> genericClass)
    {
        Object value = valueMap.get(key);
        if (value == null)
            return null;
        
        Asserts.as((value instanceof List)?null:"值不是List<T>格式，请不要使用getValueList方法");
        return (List<T>)value;
    }
    
    @SuppressWarnings("unchecked")
    public <T> MapSV<T> getValueMap(String key, Class<T> genericClass)
    {
        Object value = valueMap.get(key);
        if (value == null)
            return null;
        
        Asserts.as((value instanceof MapSV)?null:"值不是MapSV<V>格式，请不要使用getValueMap方法");
        return (MapSV<T>)value;
    }
    
    /**
     * 有条件判断是否有值，如果valueMap有值则返回valueMap中的true/false，如果没有，则通过类和静态方法名，返回true/false
     * 注意：1.如果valueMap中有值，值不是boolean类型，返回false
     *      2.如果类和静态方法返回值不是boolean类型，返回false，如果不是静态方法或静态方法参数不是HttpSessionUser返回false
     * 
     * @param key           键值
     * @param className     类名
     * @param methodName    方法名，方法必须是静态方法，且参数为HttpSessionUser实例，如public static boolean isOpen(HttpSessionUser sessionUser){};
     * @return              =true/false
     */
    public boolean isValue(String key, String className, String staticMethodName)
    {
        if (hasValue(key))
        {//有值则取值
            Object value = getValue(key);
            return Types.isBoolean(value)?(Boolean)value:false;
        }
        
        Class<?> clazz = Z.cls().forName(className);
        Asserts.as(clazz != null?null:"判断会话属性值时，传入的类名或类别名不正确");
        
        Method method = Classes.getMethodDeep(clazz, staticMethodName, this.getClass());
        Asserts.as(method != null?null:"判断会话属性值时，传入的静态方法名未找到");
        Asserts.as(Classes.isStaticMethod(method)?null:"判断会话属性值时，传入的方法名不是静态方法");
        
        try
        {
            Object value = method.invoke(null, this);
            Asserts.as(Types.isBoolean(value)?null:"判断会话属性值时，方法返回的值不是boolean型");
            
            return (Boolean)value;
        }
        catch (Exception e)
        {//异常返回false，表示业务处理失败
            return false;
        }
    }
    
    /*******************************************************************/
    //由HttpSession回调，定义为包内可访问
    /*******************************************************************/
    
    void setSession(HttpSession session)
    {
        this.session = session;
        this.sessionName = getSessionName();
    }
    
    /*******************************************************************/
    //非本系统的会话用户属性的，多系统共享会话时会出现，定义为包内可访问
    /*******************************************************************/
    
    void removeMore(String name)
    {
        moreMap.remove(name);
    }
    
    void addMore(String name, String value)
    {
        moreMap.put(name, value);
    }
    
    HashMapSS getMoreMap()
    {
        return moreMap;
    }
    
    /*******************************************************************/
    //内部设置值，定义为包内可访问
    /*******************************************************************/
    
    void setValueGeneric(String key, Object value, String genericClassName)
    {
        valueMap.put(key, value);
        if (genericClassName != null)
        {//有泛型情况List<T>,MapSV<V>
            valueGenerics.put(key, genericClassName);
        }
    }
    
    String getValueGeneric(String key)
    {
        return valueGenerics.get(key);
    }
}
